package org.lgiavedoni.android.franq.core.place;

import java.util.List;

import org.lgiavedoni.android.franq.core.bean.WifiNetwork;
import org.lgiavedoni.android.franq.core.place.dao.PlaceDAO;
import org.lgiavedoni.android.franq.core.position.Position;
import org.lgiavedoni.android.franq.core.sync.imp.GenericDao;
import org.lgiavedoni.android.franq.event.CheckInEvent;
import org.lgiavedoni.android.franq.event.CheckOutEvent;
import org.lgiavedoni.android.franq.event.CheckPlaceEvent;
import org.lgiavedoni.android.franq.service.event.EventService;
import org.lgiavedoni.android.franq.service.log.Logger;
import org.lgiavedoni.android.franq.util.place.PlaceUtil;

import android.telephony.gsm.GsmCellLocation;

public class PlaceManager {

	private Place currentPlace = null;

	public static PlaceManager inst = new PlaceManager();

	private final PlaceDAO placeDAO;

	private PlaceManager() {
		placeDAO = PlaceDAO.inst;
		// try to set the last place
		try {
			CheckPlaceEvent lastEvent = (CheckPlaceEvent) GenericDao.inst.getLast(CheckPlaceEvent.class);
			if (lastEvent != null && lastEvent instanceof CheckInEvent) {
				// The last event is a checkin, we don't have a checkout
				currentPlace = lastEvent.getPlace();
			}
		} catch (Exception e) {
			Logger.inst.error(e);
		}
	}

	/**
	 * This method check if the current position is a new place, the same, or
	 * the user is moving to a new place
	 * 
	 * @param position
	 */
	public boolean tryToUpdatePlace(Position position) {
		if (currentPlace == null) {
			// Now we are in a new place?
			if (PlaceUtil.stateEnoughTimeInTheLastPlace()) {
				currentPlace = getOrCreate(position);
				currentPlace.addPermanence();
				placeDAO.update(currentPlace);
				EventService.inst.fireEvent(new CheckInEvent(currentPlace));
				return true;
			} else {
				// May be is not enough time
				// long checkTime =
				// ConfigService.inst.getValueAsLong(ConfigKey.PLACE_MIN_STAY_TIME)
				// + 10000;
				// Only PositionManager should update the position
				// CronService.inst.addCron(new CheckPositionCron(checkTime));
				// PositionManager.inst.tryToUpdatePosition();
				return false;
			}
		} else {
			// We still are in the same place?
			if (PlaceUtil.areTheSamePlace(currentPlace, position)) {
				// everything is correct. Nothing to do
				return true;
			} else {
				// New location
				// update?
				currentPlace.finishPermanence();
				placeDAO.update(currentPlace);

				CheckOutEvent checkOutEvent = new CheckOutEvent(currentPlace);
				EventService.inst.fireEvent(checkOutEvent);
				// Not more current place
				currentPlace = null;
				// New Place?
				return tryToUpdatePlace(position);
			}
		}
	}

	public final Place getOrCreate(Position position) {
		Place place = getPlaceByNetwors(position.getNetworks());
		if (place == null) {
			place = getPlaceByGSMCell(position.getCellLocation());
		}
		if (place == null) {
			place = getPlaceByLocation(position.getLatitude(), position.getLongitude());
		}
		if (place == null) {
			place = new Place(position);
			placeDAO.add(place);
		}
		return place;
	}

	public final Place getOrCreate(double latitude, double longitude) {
		Place place = placeDAO.getByLatLong(latitude, longitude);
		if (place == null) {
			place = new Place(latitude, longitude);
			// place.addPermanence();
			placeDAO.add(place);
		}
		return place;
	}

	public final Place getPlaceByLocation(double latitude, double longitude) {
		if (latitude == 0 || longitude == 0)
			return null;
		return placeDAO.getByLatLong(latitude, longitude);
	}

	public final Place getPlaceByGSMCell(GsmCellLocation cell) {
		if (cell == null)
			return null;
		return placeDAO.getByGSMCell(cell);
	}

	public final Place getPlaceByNetwors(List<WifiNetwork> networks) {
		if (networks == null || networks.size() == 0)
			return null;
		return placeDAO.getByNetworks(networks);
	}

	public final Place getCurrentPlace() {
		return currentPlace;
	}

}
